/*
This software is distributed under the Simplified BSD License:

Copyright (c) 2008, Chris Venter <chris.venter@gmail.com>
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, 
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, 
    	this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice, 
    	this list of conditions and the following disclaimer in the documentation 
    	and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 
DAMAGE.
*/
#ifndef GENERIK_EXCEPTIONS_H
#define GENERIK_EXCEPTIONS_H

/** \file exception.h
Declares a couple of useful exceptions and some functionality that go them.
*/

#include <string>
#include <iostream>
#include <sstream>
#include <stdexcept>

#include "macros.h"
#include "tracing.h"

/**
\def GENERIK_ASSERT(VALUE)
This macro checks the boolean value of VALUE.
If the value is false, a GENERIK_ERROR is traced, and a generik::failed_assertion exception
is thrown. Therefore the user should be notified of it even if GENERIK_TRACING is not
defined.
If it is true, a success message is traced via GENERIK_TRACER
*/
#define GENERIK_ASSERT(VALUE) \
{ \
	bool result = VALUE; \
	if (!result) \
	{ \
		GENERIK_ERROR("[FAIL] assertion [" #VALUE "] in "<<__PRETTY_FUNCTION__<<":"GENERIK_FILE_LINE); \
		throw generik::failed_assertion("["#VALUE"] is false"); \
	} \
	else \
	{ \
		GENERIK_TRACE("[PASS] assertion [" #VALUE "] in "<<__PRETTY_FUNCTION__<<":"GENERIK_FILE_LINE); \
	} \
}

#define GENERIK_ERROR_THROW(EXCEPTION, MESSAGE) \
{ \
	std::stringstream mbuf; \
	mbuf<<MESSAGE<<"\n"; \
	GENERIK_ERROR(mbuf.str()); \
	throw EXCEPTION(mbuf.str().c_str()); \
}

namespace generik
{
	
	/** An exception indicating that an assertion has failed.
	It contains information about the failed assertion.
	It is normally thrown after code in a GENERIK_ASSERT() macro evaluated to false.
	In testcode, it is intended to be caught by a basetester instance, and should not have to 
	be used by a user of this facility under normal conditions.
	*/
	struct failed_assertion
	: std::exception
	{
		const char* msg;
		failed_assertion(const char* m) : msg(m) {}
		const char* what() const throw()
		{
			return msg;
		}
	};

	/** An exception indicating that a runtime_check failed.
	It is thrown by a runtime_check instance if the assertion in its 
	constructor fails.
	
	It derives from std::runtime_error since this is a kind of specialised
	runtime error.
	*/
	struct runtime_check_exception
	: std::runtime_error
	{
		runtime_check_exception(const std::string& msg) throw()
		: std::runtime_error(msg)
		{}
		runtime_check_exception(const runtime_check_exception& rhs) throw()
		: std::runtime_error(rhs)
		{}
		~runtime_check_exception() throw()
		{}
	};
	/*
	struct runtime_check_exception
	{
		std::string message;
		runtime_check_exception(const std::string& msg)
		: message(msg)
		{}
		virtual std::string what() const
		{
			return message;
		}
	};
	*/
	
	/** A special runtime check.
	This is a special runtime check. It checks whether the two arguments passed
	to it during construction are equal, and if not it throws an exception.
	It therefore implements an assert()-type check that can be embedded in 
	constructor lists.

	It can be used by a class which needs to check the value of one of its
	construction arguments *before* the other arguments are processed.
	If this check is used in the class's constructor-list, this check can even
	be run *before* any members in the list are created.

	It assumes that the TYPE has a well-defined operator!=

	An instance of this class does not allocate any space, so except for the function
	body, it is free.
	*/
	template <typename TYPE>
	struct runtime_check
	{
		runtime_check(const TYPE& v1, const TYPE& v2)
		{
			if (v1 != v2)
			{
				std::stringstream ss;
				ss<<v1<<" is not equal to "<<v2;
				throw runtime_check_exception(ss.str()); //std::runtime_error("runtime_check failed");
			}
		}
	};
	
}


#endif


